#ifndef DUALCIRCLELIST_H
#define DUALCIRCLELIST_H

#include "DualLinkList.h"
#include "LinuxList.h"

namespace DSLib
{

template <typename T>
class DualCircleList : public DualLinkList<T>
{
protected:
	struct Node : public Object
	{
		list_head list;
		T value;
	};

	list_head* position(int i) const
	{
		list_head* ret = const_cast<list_head*>(&m_header);

		i = mod(i);

		for (int p = 0; p < i; p++)
		{
			ret = ret->next;
		}

		return ret;
	}

	int mod(int i) const
	{
		return (this->m_length == 0 ? 0 : (i % this->m_length));
	}

	list_head m_header;
	list_head* m_current;

	Node node;
	list_head* ld = &node.list;



public:
	DualCircleList()
	{
		this->m_length = 0;
		this->m_step = 1;
		m_current = NULL;
		INIT_LIST_HEAD(&m_header);
	}

	bool insert(int i, const T& e)
	{
		bool ret = true;
		i = i % (this->m_length + 1);
		
		Node* node = new Node();

		if (node != NULL)
		{
			node->value = e;

			list_add(&node->list, position(i)->next);

			this->m_length++;
		}
		else
		{
			THROW_EXCEPTION(NoEnoughMemoryException, "alloc memory failed!");
		}

		return ret;
	}

	bool insert(const T& e)
	{
		return insert(this->m_length - 1, e);
	}

	bool remove(int i)
	{
		bool ret = true;

		i = mod(i);

		ret = ((0 <= i) && (i < this->m_length));

		if (ret)
		{
			list_head* toDel = position(i)->next;

			if (m_current == toDel)
			{
				m_current = toDel->next;
			}

			list_del(toDel);
			this->m_length--;

			delete list_entry(toDel, Node, list);
		}
		
		return ret;
	}

	bool set(int i, const T& e)
	{
		bool ret = true;

		i = mod(i);

		ret = ((0 <= i) && (i < this->m_length));

		if (ret)
		{
			list_entry(position(i)->next, Node, list)->value = e;
		}

		return ret;
	}

	bool get(int i, T& e) const
	{

		bool ret = true;

		i = mod(i);

		ret = ((0 <= i) && (i < this->m_length));

		if (ret)
		{
			e = list_entry(position(i)->next, Node, list)->value;
		}

		return ret;
	}

	T get(int i) const
	{
		T v;

		if (get(i, v))
		{
			return v;
		}
		else
		{
			THROW_EXCEPTION(IndexOutOfBoundsException, "index i out of range!");
		}
	}

	T& operator [] (int i)
	{
		i = mod(i);

		if ((0 <= i) && (i < this->m_length))
		{
			return list_entry(position(i)->next, Node, list)->value;
		}
		else
		{
			THROW_EXCEPTION(IndexOutOfBoundsException, "index i out of range!");
		}
	}

	T operator [] (int i) const
	{
		return const_cast<DualCircleList<T>*>(this)[i];
	}

	int find(const T& e) const
	{
		int ret = -1;
		int i = 0;

		list_head* slider = NULL;
		list_for_each(slider, &m_header)
		{
			Node* node = list_entry(slider, Node, list);

			if (node->value == e)
			{
				ret = i;
				break;
			}

			i++;
		}

		return ret;
	}

	void clear()
	{
		while (this->m_length > 0)
		{
			remove(0);
		}
	}

	bool move(int i, int step = 1)
	{
		i = mod(i);

		bool ret = ((0 <= i) && (i < this->m_length) && (step > 0));

		if (ret)
		{
			m_current = position(i)->next;
			this->m_step = step;
		}
		return ret;
	}

	bool isEnd() const
	{
		return ((this->m_length == 0) || (m_current == NULL));
	}

	T current()
	{
		if (isEnd())
		{
			THROW_EXCEPTION(InvaildParameterException, "current node is Null");
		}

		return list_entry(m_current, Node, list)->value;
	}

	bool next()
	{
		int i = 0;

		while (i < this->m_step)
		{
			if (m_current != &m_header)
			{
				m_current = m_current->next;
				i++;
			}
			else
			{
				m_current = m_current->next;
			}
		}

		if (m_current == &m_header)
			m_current = m_current->next;

		return (i == this->m_step);
	}

	bool pre()
	{
		int i = 0;

		while (i < this->m_step)
		{
			if (m_current != &m_header)
			{
				m_current = m_current->prev;
				i++;
			}
			else
			{
				m_current = m_current->prev;
			}
		}

		if (m_current == &m_header)
			m_current = m_current->prev;

		return (i == this->m_step);
	}

	~DualCircleList()
	{
		clear();
	}
};

}







#endif